using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Engine.Components.Workers;

namespace Engine.Components.Abstract
{
    public abstract class WorkerBase : Interface.IWorker
    {
        #region CONSTRUCTOR
        protected WorkerBase()
        {
            _outputTasks = Job.CreateJob();
        }
        #endregion

        #region PRIVATE
        string GetReadInfo(object o)
        {
            return this.ToString() + " read " + o.ToString();
        }
        string GetProcessedInfo(object o)
        {
            return this.ToString() + " processed " + o.ToString();
        }
        string GetProducedInfo(object o)
        {
            return this.ToString() + " produced " + o.ToString();
        }

        #endregion


        #region Interface.IWorker

        int _processedItems = 0;
        public int ProcessedItems
        {
            get { return _processedItems; }
            private set { _processedItems = value; }
        }

        int _totalItems;
        public int TotalItems
        {
            get { return _totalItems; }
            private set { _totalItems = value; }
        }

        int _producedItems = 0;
        public int ProducedItems
        {
            get { return _producedItems; }
            private set { _producedItems = value; }
        }

        Thread _consumerThread;
        public Thread ConsumerThreat
        {
            get { return _consumerThread; }
        }

        protected Components.Workers.Job _inputTasks;
        public Components.Workers.Job InputTasks
        {
            set
            {
                _inputTasks = value;
                this.StartProduce();
            }
        }

        private Components.Workers.Job _outputTasks;
        public Components.Workers.Job OutputTasks
        {
            get { return _outputTasks; }
        }


        public void StartProduce()
        {
            _consumerThread = new Thread(OnConsume);
            _consumerThread.Start();
        }

        public void Terminate(bool kill)
        {
            this._inputTasks.SyncEvents.ExitThreadEvent.Set();
        }

        #endregion

        #region VIRTUAL
        protected virtual void OnConsume()
        {

            JobStatus sts = JobStatus.NoMoreJob;
            while ((sts = ((JobStatus)WaitHandle.WaitAny(_inputTasks.SyncEvents.EventArray))) != JobStatus.JobTerminated)
            {
                try
                {
                    object o = null;
                    long count = 0;
                    if (sts == JobStatus.NoMoreJob)
                    {
                        count = _inputTasks.Queue.Count;
                        if (count > 0)
                        {
                            o = _inputTasks.Queue.Dequeue();
                            this.ProgressHandler.WriteToOutput(GetReadInfo(o), HunterPluginSDK.LogPriority.DEBUG); 
                            TotalItems++;
                        }
                        count = _inputTasks.Queue.Count;
                    }
                    else
                        lock (_inputTasks.Queue)
                        {
                            count = _inputTasks.Queue.Count;
                            if (count > 0)
                            {
                                o = _inputTasks.Queue.Dequeue();
                                this.ProgressHandler.WriteToOutput(GetReadInfo(o), HunterPluginSDK.LogPriority.DEBUG); 
                                TotalItems++;
                            }
                            count = _inputTasks.Queue.Count;
                        }
                    if (o != null)
                    {
                        this.DoMyJob(o);
                        this.ProgressHandler.WriteToOutput(GetProcessedInfo(o), HunterPluginSDK.LogPriority.DEBUG); 
                        this.ProcessedItems++;
                    }

                    if (sts == JobStatus.NoMoreJob && count == 0)//queue empty, no more tasks -> exit then
                    {
                        this.OutputTasks.SyncEvents.NoMoreEvent.Set();
                        break;
                    }
                }
                catch (Exception e)
                {
                    string se = e.ToString();
                }

            }
            if (sts == JobStatus.JobTerminated)
                this.OutputTasks.SyncEvents.ExitThreadEvent.Set();
        }

        //abstract protected void Produce();
        abstract protected void DoMyJob(object o);
        #endregion

        #region PROTECTED
        protected HunterPluginSDK.Interface.IProgressHandler ProgressHandler;
        protected void OnProduced(object o)
        {
            lock (OutputTasks.Queue)
            {
                OutputTasks.Queue.Enqueue(o);
                OutputTasks.SyncEvents.NewItemEvent.Set();
                this.ProgressHandler.WriteToOutput(GetProducedInfo(o), HunterPluginSDK.LogPriority.DEBUG); 
                ProducedItems++;
            }
        }
        #endregion

    }
}
